/*
-----------------------------------------------------------------------------
This source file is part of the OGRE Reference Application, a layer built
on top of OGRE(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreRefAppPlayerBase.h"
#include "OgreRefAppBall.h"
#include "OgreRefAppGoal.h"



namespace OgreRefApp
{

    //-------------------------------------------------------------------------
    PlayerBase::PlayerBase( const String& name, player_role    role ) : ApplicationObject(name)
    {
        m_pSterringBehavior = new SteeringBehavior(this);
        m_PlayerRole = role;
    }
    //-------------------------------------------------------------------------
    PlayerBase::~PlayerBase()
    {

    }

    //----------------------------- TrackBall --------------------------------
    //
    //  sets the player's heading to point at the ball
    //------------------------------------------------------------------------
    void PlayerBase::TrackBall()
    {
      //RotateHeadingToFacePosition(Ball()->Pos());
    }


    //------------------------- WithinFieldOfView ---------------------------
    //
    //  returns true if subject is within field of view of this player
    //-----------------------------------------------------------------------
    bool PlayerBase::PositionInFrontOfPlayer(Ogre::Vector3 position)
    {
      /*
      Vector2D ToSubject = position - Pos();

      if (ToSubject.Dot(Heading()) > 0)

        return true;

      else

        return false;
      */

      return true;
    }

    //------------------------- IsThreatened ---------------------------------
    //
    //  returns true if there is an opponent within this player's
    //  comfort zone
    //------------------------------------------------------------------------
    bool PlayerBase::isThreatened()
    {
      //check against all opponents to make sure non are within this
      //player's comfort zone
      std::vector<PlayerBase*>::const_iterator curOpp;
      curOpp = Team()->Opponents()->Members().begin();

      for (curOpp; curOpp != Team()->Opponents()->Members().end(); ++curOpp)
      {
        //calculate distance to the player. if dist is less than our
        //comfort zone, and the opponent is infront of the player, return true
        if (PositionInFrontOfPlayer((*curOpp)->getPosition()) &&
           (getPosition().squaredDistance( (*curOpp)->getPosition()) < PlayerComfortZoneSq))
        {
          return true;
        }

      }// next opp

      return false;
    }

    bool PlayerBase::BallWithinKeeperRange()
    {
      return (getPosition().squaredDistance( getBall()->getPosition() ) < KeeperInBallRangeSq);
    }

    bool PlayerBase::BallWithinReceivingRange()
    {
      return (getPosition().squaredDistance( getBall()->getPosition() ) < BallWithinReceivingRangeSq);
    }

    bool PlayerBase::BallWithinKickingRange()
    {
      return (getBall()->getPosition().squaredDistance( getPosition()) < PlayerKickingDistanceSq);
    }

    bool PlayerBase::isControllingPlayer()
    {return Team()->ControllingPlayer()==this;}

    bool PlayerBase::isClosestTeamMemberToBall()
    {
      return Team()->PlayerClosestToBall() == this;
    }

    Ball* PlayerBase::getBall()
    {

            return m_pTeam->Pitch()->ball();
    }

    bool PlayerBase::AtTarget()
    {
      return (getPosition().squaredDistance( Steering()->GetTarget() ) < PlayerInTargetRangeSq );
    }

    Region* PlayerBase::HomeRegion()
    {
      return m_iHomeRegion;
    }

    SoccerPitch* PlayerBase::Pitch()
    {
      return Team()->Pitch();
    }

    bool PlayerBase::isAheadOfAttacker()
    {
      return fabs(getPosition().x - Team()->OpponentsGoal()->Center().x) <
             fabs(Team()->ControllingPlayer()->getPosition().x - Team()->OpponentsGoal()->Center().x);
    }


    //----------------------------- FindSupport -----------------------------------
    //
    //  determines the player who is closest to the SupportSpot and messages him
    //  to tell him to change state to SupportAttacker
    //-----------------------------------------------------------------------------
    void PlayerBase::FindSupport()
    {
      //if there is no support we need to find a suitable player.
      if (Team()->SupportingPlayer() == NULL)
      {

        PlayerBase* BestSupportPly = Team()->DetermineBestSupportingAttacker();
        return;
        Team()->SetSupportingPlayer(BestSupportPly);

        ApplicationObject::CollisionInfo collInfo;
        collInfo.Msg = Msg_SupportAttacker;
        collInfo.sender = this;


        Team()->SupportingPlayer()->handleMessage( collInfo );

        /*
        Dispatcher->DispatchMsg(SEND_MSG_IMMEDIATELY,
                                ID(),
                                Team()->SupportingPlayer()->ID(),
                                Msg_SupportAttacker,
                                NULL);
        */
      }

      PlayerBase* BestSupportPly = Team()->DetermineBestSupportingAttacker();

      //if the best player available to support the attacker changes, update
      //the pointers and send messages to the relevant players to update their
      //states
      if (BestSupportPly && (BestSupportPly != Team()->SupportingPlayer()))
      {

        if (Team()->SupportingPlayer())
        {
          /*
          Dispatcher->DispatchMsg(SEND_MSG_IMMEDIATELY,
                                  ID(),
                                  Team()->SupportingPlayer()->ID(),
                                  Msg_GoHome,
                                  NULL);
          */

            ApplicationObject::CollisionInfo collInfo;
            collInfo.Msg = Msg_GoHome;
            collInfo.sender = this;


            Team()->SupportingPlayer()->handleMessage( collInfo );
        }



        Team()->SetSupportingPlayer(BestSupportPly);

        /*
        Dispatcher->DispatchMsg(SEND_MSG_IMMEDIATELY,
                                ID(),
                                Team()->SupportingPlayer()->ID(),
                                Msg_SupportAttacker,
                                NULL);

        */

        ApplicationObject::CollisionInfo collInfo;
        collInfo.Msg = Msg_SupportAttacker;
        collInfo.sender = this;


        Team()->SupportingPlayer()->handleMessage( collInfo );

      }
    }

    bool PlayerBase::InHomeRegion()
    {
      if (m_PlayerRole == goal_keeper)
      {
        return m_iHomeRegion->Inside(Ogre::Vector2(getPosition().x, getPosition().y), Region::normal);
      }
      else
      {
        return m_iHomeRegion->Inside(Ogre::Vector2(getPosition().x, getPosition().y), Region::halfsize);
      }
    }

    bool PlayerBase::InHotRegion()
    {
      return fabs(getPosition().y - Team()->OpponentsGoal()->Center().y ) <
             Pitch()->playingArea()->Length()/3.0;
    }

    bool PlayerBase::isClosestPlayerOnPitchToBall()
    {
      return isClosestTeamMemberToBall() &&
             (DistSqToBall() < Team()->Opponents()->ClosestDistToBallSq());
    }

    void PlayerBase::SetHomeRegion(int NewRegion)
    {
                    #ifdef __DEBUGON__
    std::cout << std::endl << "ChangePlayerHomeRegions " << (NewRegion) << std::endl << std::endl;
    #endif
        m_iHomeRegion = m_pTeam->Pitch()->getRegionFromIndex(NewRegion);
    }


}
